package com.bigknow.appstore.web.base.controller.auth;

import com.bigknow.appstore.auth.oauth.OAuthTokenxRequest;
import com.bigknow.appstore.auth.oauth.token.OAuthTokenHandleDispatcher;
import com.bigknow.appstore.auth.web.WebUtils;
import com.bigknow.appstore.web.base.entity.User;
import com.bigknow.appstore.web.console.app.Application;
import com.bigknow.appstore.web.console.app.OauthCode;
import com.bigknow.appstore.web.console.service.impl.ApplicationService;
import com.bigknow.appstore.web.framework.util.SpringUtils;

import org.apache.oltu.oauth2.as.response.OAuthASResponse;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.OAuthResponse;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;

import org.mongodb.morphia.Datastore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

/**
 * 2016/9/14
 *
 * @author zhangwei
 */
@Controller
@RequestMapping(value = "/oauth")
public class OauthTokenController {

    @Autowired
    private Datastore ds;

    @Autowired
    private ApplicationService applicationService;

    @Autowired
    protected SpringUtils springUtils;

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    public SpringUtils getSpringUtils() throws Exception {
        return springUtils;
    }

    public Object getBean(String beanName) throws Exception {
        if (beanName == null)
            return null;
        return getSpringUtils().getBean(beanName);
    }

    /**
     * Handle grant_types as follows:
     * <p>
     * grant_type=authorization_code
     * grant_type=password
     * grant_type=refresh_token
     * grant_type=client_credentials
     *
     * @param request  HttpServletRequest
     * @param response HttpServletResponse
     * @throws OAuthSystemException
     */
    @RequestMapping("/token")
    public void authorize(HttpServletRequest request, HttpServletResponse response) throws OAuthSystemException {
        try {
            OAuthTokenxRequest tokenRequest = new OAuthTokenxRequest(request);
            OAuthTokenHandleDispatcher tokenHandleDispatcher = new OAuthTokenHandleDispatcher(tokenRequest, response);
            tokenHandleDispatcher.dispatch();
        } catch (OAuthProblemException e) {
            //exception
            OAuthResponse oAuthResponse = OAuthASResponse
                    .errorResponse(HttpServletResponse.SC_FOUND)
                    .location(e.getRedirectUri())
                    .error(e)
                    .buildJSONMessage();
            WebUtils.writeOAuthJsonResponse(response, oAuthResponse);
        }
    }

    @RequestMapping(value = "/code")
    public ModelAndView toLogin(HttpServletRequest request, HttpServletResponse response, String client_id, String state, String redirect_uri) throws IOException {
        Subject subject = SecurityUtils.getSubject();
        User user = (User) subject.getPrincipal();
        if ((subject.isAuthenticated() || subject.isRemembered())) {
            //app store用户已登陆
            com.bigknow.appstore.web.console.app.OauthCode _code = ds.find(com.bigknow.appstore.web.console.app.OauthCode.class).filter("client_id", client_id).get();
            String code;
            if (_code == null) {
                code = UUID.randomUUID().toString();
                OauthCode oauthCode = new OauthCode();
                oauthCode.setClient_id(client_id);
                oauthCode.setCreate_time(System.currentTimeMillis());
                oauthCode.setCode(code);
                ds.save(oauthCode);
            } else {
                code = _code.getCode();
            }
            Application app = ds.find(Application.class).filter("ssoConfig.clientId", client_id).get();
            if (app != null) {
                response.sendRedirect(applicationService.getUrl(app.getId()) + "/" + app.getSsoConfig().getRedirectURL() + "?code=" + code + "&state=" + state + "&userId=" + user.getId());
            }
            return null;
        } else {
            //app store用户未登陆
            ModelAndView modelAndView = new ModelAndView("oauth_login");
            modelAndView.addObject("client_id", client_id);
            modelAndView.addObject("state", state);
            modelAndView.addObject("redirect_uri", redirect_uri);
            return modelAndView;
        }
    }

}
